package spring.cloud.tasks.executor.executor.task.task_item_execute;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import spring.cloud.tasks.common.Threads;
import spring.cloud.tasks.executor.ApplicationContextUtils;
import spring.cloud.tasks.executor.executor.task.TaskExecutor;
import spring.cloud.tasks.executor.executor.task.execute_runtime_context.TaskItemExecuteRuntimeContext;
import spring.cloud.tasks.executor.task.api.InterruptedException;
import spring.cloud.tasks.executor.task.api.Task;
import spring.cloud.tasks.executor.task.api.TaskInfoManager;

import java.util.Date;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Setter
@Getter
public class TaskItemExecute {
    public String taskId;
    public String taskInstanceId;
    public String taskStage;
    public String taskStage$type;
    public int taskStage$type$index;
    //
    protected final String xid;
    //
    private String taskDataRangeRule;
    private String taskItemInfo;
    //
    private String taskProperties;
    private String taskInstanceProperties;
    protected String taskItemIndexProperties;

    protected Date nextFireDate;
    protected final Integer secondAfterTaskStopCommandInstructed;
    public volatile boolean needStop = false;//外部指令
    protected TaskExecutor taskExecutor;
    //
    protected AtomicInteger status = new AtomicInteger(Status.RUNNING);
    protected boolean executed = false;//业务流程是否已经执行
    protected java.lang.Thread taskItemExecuteTaskThread;
    protected long startTime;
    protected long endTime;
    protected volatile TaskItemExecuteRuntimeContext taskItemExecuteRuntimeContext;
    private String threadName;

    //
    public TaskItemExecute(TaskExecutor taskExecutor,
                           String taskId,
                           String taskInstanceId,
                           String taskStage,
                           String taskStage$type,
                           int taskStage$type$index,
                           //
                           String xid,
                           //
                           String taskDataRangeRule,//
                           String taskItemInfo,//
                           //
                           String taskProperties, //
                           String taskInstanceProperties,//
                           String taskItemIndexProperties, //
                           Integer secondAfterTaskStopCommandInstructed) {//
        this.taskExecutor = taskExecutor;
        this.taskId = taskId;
        this.taskInstanceId = taskInstanceId;
        this.taskStage = taskStage;
        this.taskStage$type = taskStage$type;
        this.taskStage$type$index = taskStage$type$index;
        //
        this.xid = xid;
        //
        this.taskDataRangeRule = taskDataRangeRule;
        this.taskInstanceProperties = taskInstanceProperties;
        this.taskItemInfo = taskItemInfo;
        //
        this.taskProperties = taskProperties;
        this.taskItemIndexProperties = taskItemIndexProperties;
        //
        this.secondAfterTaskStopCommandInstructed = secondAfterTaskStopCommandInstructed;
    }

    public void bind(TaskItemExecuteRuntimeContext taskItemExecuteRuntimeContext) {
        this.taskItemExecuteRuntimeContext = taskItemExecuteRuntimeContext;
    }

    public boolean setTimeoutWhenStatusInit() {
        return status.compareAndSet(Status.RUNNING, Status.TIMEOUT);
    }

    public boolean setForceStopWhenStatusInit() {
        return status.compareAndSet(Status.RUNNING, Status.KILLED);
    }

    public void executeAndGetTaskItemExecuteResult() {
        /**
         *taskItemExecute运行在taskItemExecuteTask所在的Thread
         */
        taskItemExecuteTaskThread = java.lang.Thread.currentThread();
        try {
            //进入休眠状态 时间到了后不会立即进入可执行状态。该代码应该在具体执行的时候判断。
            long nowTime = System.currentTimeMillis();
            long delayMS = this.getNextFireDate().getTime() + 1L/**保证能够能够实现业务对时间上的准确性*/ - nowTime;
            if (delayMS > 0) {
                try {
                    TimeUnit.MILLISECONDS.sleep(delayMS);
                } catch (java.lang.InterruptedException e) {
                    e.printStackTrace();
                }
            }
            beforeExecute();
            sleep(secondAfterTaskStopCommandInstructed);
            execute();
            //这以后就不能进行强制杀的必要了
            taskItemExecuteTaskThread = null;
            // 在此之后，不能再强制停止本线程
            executed = true;
        } catch (Throwable t) {
            //这以后就不能进行强制杀的必要了
            taskItemExecuteTaskThread = null;
            // 在此之后，不能再强制停止本线程
            executed = true;
            // 不是超时，不是强制停止。
            //this.taskItemExecuteResult = new TaskItemExecuteControlContext(TaskItemExecuteStatus.ERROR, t.getMessage());
            this.taskItemExecuteRuntimeContext.setStatus(Status.ERROR);
            this.taskItemExecuteRuntimeContext.setMessage(t.getMessage());
        } finally {
            afterExecute();
        }
    }

    public void sleep(Integer secondAfterTaskStopCommandInstructed) {
        if (secondAfterTaskStopCommandInstructed != null && secondAfterTaskStopCommandInstructed > 0) {
            for (int i = 1; i <= secondAfterTaskStopCommandInstructed; i++) {
                Threads.sleep();
            }
        }
    }

    public void beforeExecute() {
        this.startTime = System.currentTimeMillis();
    }

    public void afterExecute() {
        this.endTime = System.currentTimeMillis();
    }

    public long getExecutionTime() {
        return endTime - startTime;
    }

    public void execute() {
        try {
            /**
             * BizTask必须获取的是原型实例,其他情况需要自己改造
             */
            Task bean = (Task) ApplicationContextUtils.getApplicationContext().getBean(TaskInfoManager.getBeanId(xid));
            bean.init(this,//
                    taskItemExecuteRuntimeContext,//
                    taskId, //
                    taskInstanceId, //
                    taskStage, //
                    taskStage$type, //
                    taskStage$type$index, //
                    xid,    //
                    taskProperties,//
                    taskInstanceProperties, //
                    taskItemIndexProperties);
            bean.execute();
            status.set(Status.SUCCESS);
            taskItemExecuteRuntimeContext.setStatus(Status.SUCCESS);

        } catch (InterruptedException e) {
            String message = e.getMessage();
            taskItemExecuteRuntimeContext.setStatus(Status.ERROR);
            taskItemExecuteRuntimeContext.setMessage(message);
        } catch (Throwable e) {
            String message = e.getMessage();
            taskItemExecuteRuntimeContext.setStatus(Status.ERROR);
            taskItemExecuteRuntimeContext.setMessage(message);
        }
    }

}
